﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO;
using PGMHelper;
using Newtonsoft.Json;
using System.Windows.Forms.DataVisualization.Charting;

namespace Spectrum
{
    

    [JsonObject(MemberSerialization.OptIn)]
    /// <summary>
    /// 加速度激励时程
    /// </summary>
    public class AccelSet
    {
        #region Variables

        [JsonProperty]
        /// <summary>
        /// 初始的加速度时程曲线
        /// </summary>
        private List<AccelParam> OriginAccelList_ { set; get; }

        /// <summary>
        /// 目标时程曲线
        /// </summary>
        private List<AccelParam> TargetAccelList_ { set; get; }

        /// <summary>
        /// 目标加速度时间间隔
        /// </summary>
        private float TargetAccelTimeInterval { set; get; }

        /// <summary>
        /// 目标加速度时间最大值
        /// </summary>
        private float TargetAccelTimeLength { set; get; }

        #endregion

        #region Properties

        /// <summary>
        /// 获得时程最大时间
        /// </summary>
        public float OriginAccelMaxTime
        {
            get
            {
                if (this.OriginAccelList_.Count == 0) return 0;
                this.OriginAccelList_.OrderBy("Time");
                return this.OriginAccelList_.Last().Time;
            }
        }

        /// <summary>
        /// 原地震波峰值
        /// </summary>
        public float OriginAccelPGA
        {
            get
            {
                var accelList = (from accel in this.OriginAccelList_ select accel.Accel).ToList();
                var min = accelList.Min();
                var max = accelList.Max();
                return Math.Max(Math.Abs(min), Math.Abs(max));
            }
        }

        /// <summary>
        /// 地震波峰值对应的时刻
        /// </summary>
        public float OriginAccelPGATime
        {
            get
            {
                var accelMax = new float();
                var accleParam = new AccelParam();
                foreach (var accel in OriginAccelList_)
                {
                    if(Math.Abs(accel.Accel) >= accelMax)
                    {
                        accelMax = Math.Abs(accel.Accel);
                        accleParam = accel;
                    }
                }
                return accleParam.Time;
            }
        }

        /// <summary>
        /// 数据点数目
        /// </summary>
        public int Count
        {
            get
            {
                return this.OriginAccelList_.Count;
            }
        }

        /// <summary>
        /// 有效持续时间
        /// </summary>
        public float EffectiveDuration
        {
            get
            {
                //获得PGA
                var pga = this.OriginAccelPGA;
                //获得首次达到峰值10%的时刻
                var subPGA = 0.1F * pga;
                var Tstart = new float(); var Estart = new float();
                //往前遍历
                for(int index =0; index < this.OriginAccelList_.Count; index++)
                {
                    if(Math.Abs(this.OriginAccelList_[index].Accel) >= subPGA)
                    {
                        Tstart = this.OriginAccelList_[index].Time;break;
                    }
                }
                //往后遍历
                for (int index = this.OriginAccelList_.Count - 1; index >=0 ; index--)
                {
                    if (Math.Abs(this.OriginAccelList_[index].Accel) >= subPGA)
                    {
                        Estart = this.OriginAccelList_[index].Time; break;
                    }
                }
                //返回有效持时
                return Estart - Tstart;
            }
        }

        /// <summary>
        /// 返回原始加速度
        /// </summary>
        public List<AccelParam> OriginAccelList
        {
            get
            {
                return this.OriginAccelList_;
            }
        }

        #endregion

        /// <summary>
        /// 加速度调整
        /// </summary>
        /// <param name="factor"></param>
        public void AccelAmplitude(float factor)
        {
            this.OriginAccelList_.ForEach(param => param.Accel *= factor);
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="accelParam"></param>
        public void Add(AccelParam accelParam)
        {
            this.OriginAccelList_.Add(accelParam);
        }

        /// <summary>
        /// 系数初始加速度时程获得目标加速度时程
        /// </summary>
        public List<AccelParam> GetSpraseAccelHist(float dt, float length)
        {
            //响应是否为空
            //if (this.OriginAccelList_.Count == 0) return this.TargetAccelList_;
            //初始化
            this.TargetAccelTimeInterval = dt;
            this.TargetAccelTimeLength = length == -1 ? this.OriginAccelMaxTime :
                length;
            //决定数据点数据
            int StepNumber = (int)(this.TargetAccelTimeLength /
                this.TargetAccelTimeInterval) + 1;
            //初始加速度时程排序
            if(this.OriginAccelList_.Count != 0)
                this.OriginAccelList_.OrderBy(param => param.Time);
            //实例化
            this.TargetAccelList_ = new List<AccelParam>(StepNumber);
            //索引符号初始化(加速时程稀疏效果)
            int searchIndex = new int();
            //添加数据
            for (int step = 0; step < StepNumber; step++)
            {
                //确定时刻
                var time = step * this.TargetAccelTimeInterval;
                //判断是否越界
                if (searchIndex + 1 >= this.OriginAccelList_.Count)
                {
                    this.TargetAccelList_.Add(new AccelParam(time));
                    continue;
                }
                //记录前一步的值
                var preAccel = this.OriginAccelList_[searchIndex];
                var postAccel = this.OriginAccelList_[searchIndex + 1];
                //寻找区间
                while (time > postAccel.Time)
                {
                    //越界
                    if (++searchIndex + 1 >= this.OriginAccelList_.Count)
                        break;
                    //确定新的迭代参数
                    preAccel = postAccel;
                    postAccel = this.OriginAccelList_[searchIndex + 1];
                }
                //不越界直接进行线性插值
                this.TargetAccelList_.Add(preAccel.Interpolation(postAccel, time));
            }
            return this.TargetAccelList_;
        }

        /// <summary>
        /// 获得值列表
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public List<float> GetOriginValueList(string propertyName)
        {
            return this.OriginAccelList_.GetPropertyList(propertyName).ConvertAll(f => (float)f);
        }

        /// <summary>
        /// 获得局部加速度
        /// </summary>
        /// <param name="StartTime"></param>
        /// <param name="EndTime"></param>
        /// <returns></returns>
        public AccelSet GetPartialAccel(int StartTime, int EndTime, float dt)
        {
            //初始化
            var accel = new AccelSet();
            this.OriginAccelList_.OrderBy("Time");
            //遍历时程
            this.OriginAccelList_.ForEach(accelParam =>
            {
                //时间范围内则添加
                if (accelParam.Time >= StartTime && accelParam.Time <= EndTime)
                    accel.Add(new AccelParam
                    {
                        Accel = accelParam.Accel,
                        Time = accel.Count * dt
                    });
            });
            //返回加速度时程
            return accel;
        }

        /// <summary>
        /// 根据加速度比值进行反应谱初选
        /// </summary>
        /// <param name="factor"></param>
        /// <returns></returns>
        public Tuple<int, int> GetBoundary(double factor)
        {
            //往前遍历
            int startTime = 0; int endTime = (int)this.OriginAccelList_.Last().Time;
            //获得GPA
            var pga = this.OriginAccelPGA;
            //遍历
            for (int index = 0; index < this.OriginAccelList_.Count; index++)
            {
                if(Math.Abs(this.OriginAccelList_[index].Accel) >= factor * pga)
                {
                    startTime = (int)this.OriginAccelList_[index == 0? 0: index - 1].Time;
                    break;
                }
            }
            //遍历
            for (int index = this.OriginAccelList_.Count - 1; index >= 0; index--)
            {
                if (Math.Abs(this.OriginAccelList_[index].Accel) >= factor * pga)
                {
                    endTime = (int)this.OriginAccelList_[index == this.OriginAccelList_.Count - 1? 
                        this.OriginAccelList_.Count - 1: index + 1].Time;
                    break;
                }
            }
            //返回
            return Tuple.Create<int, int>(startTime, endTime);
        }

        /// <summary>
        /// 绘制时程曲线
        /// </summary>
        /// <param name="chart"></param>
        public void ToChart(Chart chart)
        {
            //绘图
            chart.Series.Clear();
            chart.AddSeries("地震波", SeriesChartType.Line, System.Drawing.Color.Black, 1);
            chart.Series["地震波"].Points.DataBindXY(this.GetOriginValueList("Time"),
               this.GetOriginValueList("Accel"));
            //值初始化
            var pga = this.OriginAccelPGA;
            var duration = this.OriginAccelMaxTime;
            //设定最大值
            var boundMax = pga * 2;
            //获得时间最大值
            var timeMax = duration <= 60 ? ((int)(duration / 10) + 1) * 10 :
                ((int)(duration / 20) + 1) * 20;
            chart.SetAxisBroundary(ChartAxisType.AxisX, 0, timeMax, 5);
            //设定最大值
            if (pga > 1)
            {
                //求得边界值
                boundMax = ((int)(pga / 10) + 1) * 10;
                //设定最大值
                chart.SetAxisBroundary(ChartAxisType.AxisY, (float)-boundMax, (float)boundMax, 4, 0);
            }
            else chart.SetAxisBroundary(ChartAxisType.AxisY, (float)-boundMax, (float)boundMax, 4);
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public AccelSet()
        {
            this.OriginAccelList_ = new List<AccelParam>();
            this.TargetAccelList_ = new List<AccelParam>();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="originAList"></param>
        /// <param name="dt"></param>
        /// <param name="length"></param>
        public AccelSet(List<AccelParam> originAList)
        {
            this.OriginAccelList_ = originAList;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="jumpLine"></param>
        /// <param name="linePrtNum"></param>
        /// <param name="dt"></param>
        public AccelSet(string filePath, int jumpLine, int linePrtNum, float dt)
        {
            //初始化
            this.OriginAccelList_ = new List<AccelParam>();
            //读取文件
            var strList = File.ReadAllLines(filePath).ToList();
            //跳过前方信息
            for(int index = jumpLine; index < strList.Count; index++)
            {
                //行信息为空时直接返回
                if (strList[index] == string.Empty) break;
                //拆分行信息
                var subStrList = WilsonHelper.SplitStr(strList[index]);
                //行信息是否匹配
                if (subStrList.Count < linePrtNum) break;
                //读取信息
                try
                {
                    for(int numIndex = 0; numIndex < linePrtNum; numIndex++)
                    {
                        this.OriginAccelList_.Add(new AccelParam
                        {
                            Time = this.OriginAccelList_.Count * dt,
                            Accel = Convert.ToSingle(subStrList[numIndex])
                        });
                    }
                }
                catch
                {
                    break;
                }
            }
        }

        /// <summary>
        /// 构造函数 time accel
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="jumpLine"></param>
        /// <param name="linePrtNum"></param>
        /// <param name="spilt"></param>
        public AccelSet(string filePath, int jumpLine, string spilt = ",")
        {
            //初始化
            this.OriginAccelList_ = new List<AccelParam>();
            //读取文件
            var strList = File.ReadAllLines(filePath).ToList();
            //跳过前方信息
            for (int index = jumpLine; index < strList.Count; index++)
            {
                //行信息为空时直接返回
                if (strList[index] == string.Empty) break;
                //拆分行信息
                var subStrList = WilsonHelper.SplitStr(strList[index], new string[] { spilt });
                //行信息是否匹配
                if (subStrList.Count < 2) break;
                //读取信息
                try
                {
                    this.OriginAccelList_.Add(new AccelParam
                    {
                        Time = Convert.ToSingle(subStrList[0]),
                        Accel = Convert.ToSingle(subStrList[1])
                    });
                }
                catch
                {
                    break;
                }
            }
        }
    }
}
